#ifndef _OPENPCD_PROTO_H
#define _OPENPCD_PROTO_H

/* This header file describes the USB protocol of the OpenPCD RFID reader */

#include <sys/types.h>

struct openpcd_hdr {
	u_int8_t cmd;		/* command. high nibble: class,
				 *	     low nibble: cmd */
	u_int8_t flags;
	u_int8_t reg;		/* register */
	u_int8_t val;		/* value (in case of write *) */
	u_int8_t data[0];
} __attribute__ ((packed));

#define OPCD_REV_LEN	16
struct openpcd_compile_version {
	char svnrev[OPCD_REV_LEN];
	char by[OPCD_REV_LEN];
	char date[OPCD_REV_LEN];
} __attribute__ ((packed));

#define OPENPCD_FLAG_RESPOND	0x01	/* Response requested */
#define OPENPCD_FLAG_ERROR		0x80	/* An error occurred */

enum openpcd_cmd_class {
	OPENPCD_CMD_CLS_GENERIC		= 0x0,
	/* PCD (reader) side */
	OPENPCD_CMD_CLS_RC632		= 0x1,
	//OPENPCD_CMD_CLS_LED		= 0x2,
	OPENPCD_CMD_CLS_SSC			= 0x3,
	OPENPCD_CMD_CLS_PWM			= 0x4,
	OPENPCD_CMD_CLS_ADC			= 0x5,
	OPENPCD_CMD_CLS_LIBRFID		= 0x6,
	OPENPCD_CMD_CLS_PRESENCE	= 0x7,
	/* PICC (transponder) side */
	OPENPCD_CMD_CLS_PICC		= 0xe,

	OPENPCD_CMD_CLS_USBTEST		= 0xf,
};

#define OPENPCD_REG_MAX	0x3f

#define OPENPCD_CMD_CLS(x)	(x >> 4)
#define OPENPCD_CMD(x)		(x & 0xf)

#define OPENPCD_CLS2CMD(x)	(x << 4)

/* Generic */
#define OPENPCD_CMD_GET_VERSION		(0x1|OPENPCD_CLS2CMD(OPENPCD_CMD_CLS_GENERIC))
#define OPENPCD_CMD_SET_LED			(0x2|OPENPCD_CLS2CMD(OPENPCD_CMD_CLS_GENERIC))
#define OPENPCD_CMD_GET_SERIAL		(0x3|OPENPCD_CLS2CMD(OPENPCD_CMD_CLS_GENERIC))
#define OPENPCD_CMD_GET_API_VERSION	(0x4|OPENPCD_CLS2CMD(OPENPCD_CMD_CLS_GENERIC))
#define OPENPCD_CMD_GET_ENVIRONMENT	(0x5|OPENPCD_CLS2CMD(OPENPCD_CMD_CLS_GENERIC))
#define OPENPCD_CMD_SET_ENVIRONMENT	(0x6|OPENPCD_CLS2CMD(OPENPCD_CMD_CLS_GENERIC))
#define OPENPCD_CMD_RESET			(0x7|OPENPCD_CLS2CMD(OPENPCD_CMD_CLS_GENERIC))

/* CMD_CLS_RC632 */
#define OPENPCD_CMD_WRITE_REG		(0x1|OPENPCD_CLS2CMD(OPENPCD_CMD_CLS_RC632))
#define OPENPCD_CMD_WRITE_FIFO		(0x2|OPENPCD_CLS2CMD(OPENPCD_CMD_CLS_RC632))
#define OPENPCD_CMD_WRITE_VFIFO		(0x3|OPENPCD_CLS2CMD(OPENPCD_CMD_CLS_RC632))
#define OPENPCD_CMD_REG_BITS_CLEAR	(0x4|OPENPCD_CLS2CMD(OPENPCD_CMD_CLS_RC632))
#define OPENPCD_CMD_REG_BITS_SET	(0x5|OPENPCD_CLS2CMD(OPENPCD_CMD_CLS_RC632))
#define OPENPCD_CMD_READ_REG		(0x6|OPENPCD_CLS2CMD(OPENPCD_CMD_CLS_RC632))
#define OPENPCD_CMD_READ_FIFO		(0x7|OPENPCD_CLS2CMD(OPENPCD_CMD_CLS_RC632))
#define OPENPCD_CMD_READ_VFIFO		(0x8|OPENPCD_CLS2CMD(OPENPCD_CMD_CLS_RC632))
#define OPENPCD_CMD_DUMP_REGS		(0x9|OPENPCD_CLS2CMD(OPENPCD_CMD_CLS_RC632))
#define OPENPCD_CMD_IRQ				(0xa|OPENPCD_CLS2CMD(OPENPCD_CMD_CLS_RC632))
#define OPENPCD_CMD_WRITE_REG_SET	(0xb|OPENPCD_CLS2CMD(OPENPCD_CMD_CLS_RC632))

/* CMD_CLS_SSC */
#define OPENPCD_CMD_SSC_READ		(0x1|OPENPCD_CLS2CMD(OPENPCD_CMD_CLS_SSC))
#define OPENPCD_CMD_SSC_WRITE		(0x2|OPENPCD_CLS2CMD(OPENPCD_CMD_CLS_SSC))

/* CMD_CLS_PWM */
#define OPENPCD_CMD_PWM_ENABLE		(0x1|OPENPCD_CLS2CMD(OPENPCD_CMD_CLS_PWM))
#define OPENPCD_CMD_PWM_DUTY_SET	(0x2|OPENPCD_CLS2CMD(OPENPCD_CMD_CLS_PWM))
#define OPENPCD_CMD_PWM_DUTY_GET	(0x3|OPENPCD_CLS2CMD(OPENPCD_CMD_CLS_PWM))
#define OPENPCD_CMD_PWM_FREQ_SET	(0x4|OPENPCD_CLS2CMD(OPENPCD_CMD_CLS_PWM))
#define OPENPCD_CMD_PWM_FREQ_GET	(0x5|OPENPCD_CLS2CMD(OPENPCD_CMD_CLS_PWM))

/* CMD_CLS_PICC */
#define OPENPCD_CMD_PICC_REG_WRITE	(0x1|OPENPCD_CLS2CMD(OPENPCD_CMD_CLS_PICC))
#define OPENPCD_CMD_PICC_REG_READ	(0x2|OPENPCD_CLS2CMD(OPENPCD_CMD_CLS_PICC))

/* CMD_CLS_ADC */
#define OPENPCD_CMD_ADC_READ		(0x1|OPENPCD_CLS2CMD(OPENPCD_CMD_CLS_ADC))

/* CMD_CLS_LIBRFID */
#define OPENPCD_CMD_LRFID_DETECT_IRQ	(0x1|OPENPCD_CLS2CMD(OPENPCD_CMD_CLS_LIBRFID))

/* CMD_CLS_LIBRFID */
#define OPENPCD_CMD_PRESENCE_UID_GET    (0x1|OPENPCD_CLS2CMD(OPENPCD_CMD_CLS_PRESENCE))

/* CMD_CLS_USBTEST */
#define OPENPCD_CMD_USBTEST_IN		(0x1|OPENPCD_CLS2CMD(OPENPCD_CMD_CLS_USBTEST))
#define OPENPCD_CMD_USBTEST_OUT		(0x2|OPENPCD_CLS2CMD(OPENPCD_CMD_CLS_USBTEST))

/* FIXME */
#define OPENPCD_CMD_PIO_IRQ		(0x3|OPENPCD_CLS2CMD(OPENPCD_CMD_CLS_USBTEST))

/* http://www.obdev.at/products/vusb/index.html has some explanations on how to choose PID/VID for free */
/* VID 0x16c0 in general is used for devices utilizing LibUSB driver */
/* PID 0x0888 is picked randomly */
#define OPENPCD_VENDOR_ID	0x16c0
#define OPENPCD_PRODUCT_ID	0x0888
#define OPENPCD_OUT_EP		0x01
#define OPENPCD_IN_EP		0x82
#define OPENPCD_IRQ_EP		0x83

#endif
